package cn.edu.scau.cmi.ema.service;

import java.util.List;
import java.util.Set;

import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Transactional;


import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Projections;
import org.hibernate.Session;
import cn.edu.scau.cmi.ema.dao.*;
import cn.edu.scau.cmi.ema.domain.*;
import cn.edu.scau.cmi.ema.util.CmiSqlUtil;
import cn.edu.scau.cmi.ema.domain.base.CmiPagination;
import cn.edu.scau.cmi.ema.service.base.CmiEmaService;

import java.io.IOException;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.HashSet;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import javax.persistence.Query;
import java.util.Iterator;
@Service("PackingmethodService")
@Transactional

public class PackingmethodServiceImpl extends CmiEmaService implements PackingmethodService {
	public PackingmethodServiceImpl() {
	}

	@Transactional
	public Packingmethod savePackingmethod(Packingmethod packingmethod) {
		Set<Food> existingFoodsForFood = new HashSet<Food>();

		Set<Food> selectedFoodsForFood = packingmethod.getFoodsForPackingmethod();

		if (packingmethod.getId() == null) {
			Unit unit = unitDAO.findUnitById(packingmethod.getUnit().getId());

			Packingmethod existingPackingmethod = packingmethodDAO.findPackingmethodByPhysicalPrimaryKey(
					packingmethod.getName(), packingmethod.getFee(), unit.getId());

			packingmethod.setUnit(unit);

			if (isEquals(packingmethod, existingPackingmethod)) {
				return existingPackingmethod;
			}

			packingmethod = packingmethodDAO.store(packingmethod);
			packingmethodDAO.flush();

			for (Food relatedFood : selectedFoodsForFood) {
				relatedFood.getPackingmethodsForFood().add(packingmethod);
				foodDAO.store(relatedFood);
			}
		} else {
			Packingmethod existingPackingmethod = packingmethodDAO.findPackingmethodByPrimaryKey(packingmethod.getId());

			existingFoodsForFood = existingPackingmethod.getFoodsForPackingmethod();

			Set<Food> prepareDeleteFoodsForFood = new HashSet<Food>();
			Set<Food> prepareAddFoodsForFood = new HashSet<Food>();

			prepareDeleteFoodsForFood.addAll(selectedFoodsForFood);
			prepareDeleteFoodsForFood.addAll(existingFoodsForFood);

			prepareAddFoodsForFood.addAll(selectedFoodsForFood);
			prepareAddFoodsForFood.addAll(existingFoodsForFood);

			prepareDeleteFoodsForFood.removeAll(selectedFoodsForFood);
			prepareAddFoodsForFood.removeAll(existingFoodsForFood);

			for (Food relatedFood : prepareAddFoodsForFood) {

				relatedFood.getPackingmethodsForFood().add(existingPackingmethod);
				foodDAO.store(relatedFood);
			}

			for (Food relatedFood : prepareDeleteFoodsForFood) {

				relatedFood.getPackingmethodsForFood().remove(existingPackingmethod);
				foodDAO.store(relatedFood);
			}
			packingmethod = packingmethodDAO.store(packingmethod);
			packingmethodDAO.flush();
		}

		foodDAO.flush();
		return packingmethod;
	}

	public void deletePackingmethod(Packingmethod packingmethod) {
		packingmethodDAO.remove(packingmethod);
		packingmethodDAO.flush();
	}

	@Transactional
	public void deletePackingmethods(Set<Integer> deletePackingmethodsId) {
		Query query = packingmethodDAO.createNamedQuery("deletePackingmethodsById", -1, -1);
		query.setParameter(1, deletePackingmethodsId);
		query.executeUpdate();
	}

	@Transactional
	public Set<Packingmethod> loadPackingmethods() {
		return packingmethodDAO.findAllPackingmethods();

	}

	@Transactional
	public Set<Packingmethod> loadReferencePackingmethods(Set<Packingmethod> packingmethods) {
		Iterator<Packingmethod> packingmethodsIterator = packingmethods.iterator();
		Set<Packingmethod> referencedPackingmethods = new HashSet<>();
		while (packingmethodsIterator.hasNext()) {
			Packingmethod currentPackingmethod = packingmethodsIterator.next();

			if (!currentPackingmethod.getFoodsForPackingmethod().isEmpty()) {
				referencedPackingmethods.add(currentPackingmethod);
				continue;
			}
		}
		return referencedPackingmethods;
	}

	public Set<Packingmethod> loadPackingmethodsByIdSet(Set<Integer> packingmethodIdSet) {

		Iterator<Integer> packingmethodIdIterator = packingmethodIdSet.iterator();
		Set<Packingmethod> packingmethodSet = new HashSet<>();
		while (packingmethodIdIterator.hasNext()) {
			Integer id = packingmethodIdIterator.next();
			Packingmethod currentPackingmethod = packingmethodDAO.findPackingmethodById(id);
			packingmethodSet.add(currentPackingmethod);
		}
		return packingmethodSet;
	}

	@Transactional
	public List<Packingmethod> findAllPackingmethods(Integer startResult, Integer maxRows) {
		return new java.util.ArrayList<Packingmethod>(packingmethodDAO.findAllPackingmethods(startResult, maxRows));
	}

	@Transactional
	public Packingmethod findPackingmethodByPrimaryKey(Integer id) {
		return packingmethodDAO.findPackingmethodByPrimaryKey(id);
	}

	@Transactional
	public Integer countPackingmethods() {
		return ((Long) packingmethodDAO.createQuerySingleResult("select count(o) from Packingmethod o")
				.getSingleResult()).intValue();
	}

	@Transactional
	public Integer countPackingmethods(CmiPagination page) {
		String sql = CmiSqlUtil.createCountHql(page, Packingmethod.class);
		return ((Long) packingmethodDAO.createQuerySingleResult(sql).getSingleResult()).intValue();
	}

	/**
	 * search for name with ajax
	 * 
	 */
	@Transactional
	public Integer countPackingmethodsByName(String queryName) {
		Query query = packingmethodDAO.createNamedQuery("countPackingmethodsByName", -1, -1);
		query.setParameter(1, queryName);
		return new Long((long) query.getSingleResult()).intValue();
	}

	@Transactional
	public Integer countPackingmethodsByDetachedCriteria(CmiPagination page) {
		DetachedCriteria detachedCriteria = CmiSqlUtil.createDetachedCriteria(page, Packingmethod.class);
		Session session = entityManager.unwrap(Session.class);
		detachedCriteria.setProjection(Projections.rowCount());
		return new Long((long) detachedCriteria.getExecutableCriteria(session).uniqueResult()).intValue();
	}

	public Map<String, ?> loadPackingmethodObjectReferencedSet(Packingmethod packingmethod) {
		HashMap<String, Object> objectReferencedSetMap = new HashMap<>();
		if (packingmethod.getUnit() != null) {

			Set<Integer> unitIds = new HashSet<Integer>();
			unitIds.add(packingmethod.getUnit().getId());
			objectReferencedSetMap.put("unitIds", unitIds);
		}

		Set<Integer> foodsIds = new HashSet<Integer>();
		for (Food food : packingmethod.getFoodsForPackingmethod()) {
			foodsIds.add(food.getId());
		}
		objectReferencedSetMap.put("foodsIds", foodsIds);

		return objectReferencedSetMap;
	}

	public Map<String, ?> loadPackingmethodClassReferencedSet(Packingmethod packingmethod) {
		HashMap<String, Object> classReferencedSetMap = new HashMap<>();
		classReferencedSetMap.put("units", unitDAO.findAllUnits());
		classReferencedSetMap.put("foods", foodDAO.findAllFoods());

		return classReferencedSetMap;
	}

	public boolean isEquals(Packingmethod packingmethod, Object obj) {
		if (obj == packingmethod)
			return true;
		if (!(obj instanceof Packingmethod))
			return false;
		Packingmethod comparedPackingmethod = (Packingmethod) obj;
		if (!CheckPropertyEqual(packingmethod.getName(), comparedPackingmethod.getName())) {
			return false;
		}
		if (!CheckPropertyEqual(packingmethod.getFee(), comparedPackingmethod.getFee())) {
			return false;
		}
		if (!CheckPropertyEqual(packingmethod.getUnit().getId(), comparedPackingmethod.getUnit().getId())) {
			return false;
		}
		return true;
	}

	public static <T> boolean CheckPropertyEqual(T originProperty, T comparedProperty) {
		// 基本类型经过参数传递后会自动装箱
		String[] className = originProperty.getClass().getName().split("\\.");
		if (className[0].equals("java") && className[1].equals("math")) {
			return ((Comparable) originProperty).compareTo(comparedProperty) == 0 ? true : false;
		} else {
			return originProperty.equals(comparedProperty);
		}
	}
}

